/*
Copyright 2022 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package io.kubernetes.client.openapi.models;

import io.kubernetes.client.fluent.BaseFluent;
import io.kubernetes.client.fluent.Nested;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.function.Predicate;

/** Generated */
@SuppressWarnings(value = "unchecked")
public class V1beta1FlowSchemaSpecFluentImpl<A extends V1beta1FlowSchemaSpecFluent<A>>
    extends BaseFluent<A> implements V1beta1FlowSchemaSpecFluent<A> {
  public V1beta1FlowSchemaSpecFluentImpl() {}

  public V1beta1FlowSchemaSpecFluentImpl(V1beta1FlowSchemaSpec instance) {
    this.withDistinguisherMethod(instance.getDistinguisherMethod());

    this.withMatchingPrecedence(instance.getMatchingPrecedence());

    this.withPriorityLevelConfiguration(instance.getPriorityLevelConfiguration());

    this.withRules(instance.getRules());
  }

  private V1beta1FlowDistinguisherMethodBuilder distinguisherMethod;
  private Integer matchingPrecedence;
  private V1beta1PriorityLevelConfigurationReferenceBuilder priorityLevelConfiguration;
  private ArrayList<V1beta1PolicyRulesWithSubjectsBuilder> rules;

  /**
   * This method has been deprecated, please use method buildDistinguisherMethod instead.
   *
   * @return The buildable object.
   */
  @Deprecated
  public V1beta1FlowDistinguisherMethod getDistinguisherMethod() {
    return this.distinguisherMethod != null ? this.distinguisherMethod.build() : null;
  }

  public V1beta1FlowDistinguisherMethod buildDistinguisherMethod() {
    return this.distinguisherMethod != null ? this.distinguisherMethod.build() : null;
  }

  public A withDistinguisherMethod(V1beta1FlowDistinguisherMethod distinguisherMethod) {
    _visitables.get("distinguisherMethod").remove(this.distinguisherMethod);
    if (distinguisherMethod != null) {
      this.distinguisherMethod = new V1beta1FlowDistinguisherMethodBuilder(distinguisherMethod);
      _visitables.get("distinguisherMethod").add(this.distinguisherMethod);
    } else {
      this.distinguisherMethod = null;
      _visitables.get("distinguisherMethod").remove(this.distinguisherMethod);
    }
    return (A) this;
  }

  public Boolean hasDistinguisherMethod() {
    return this.distinguisherMethod != null;
  }

  public V1beta1FlowSchemaSpecFluent.DistinguisherMethodNested<A> withNewDistinguisherMethod() {
    return new V1beta1FlowSchemaSpecFluentImpl.DistinguisherMethodNestedImpl();
  }

  public V1beta1FlowSchemaSpecFluent.DistinguisherMethodNested<A> withNewDistinguisherMethodLike(
      V1beta1FlowDistinguisherMethod item) {
    return new V1beta1FlowSchemaSpecFluentImpl.DistinguisherMethodNestedImpl(item);
  }

  public V1beta1FlowSchemaSpecFluent.DistinguisherMethodNested<A> editDistinguisherMethod() {
    return withNewDistinguisherMethodLike(getDistinguisherMethod());
  }

  public V1beta1FlowSchemaSpecFluent.DistinguisherMethodNested<A> editOrNewDistinguisherMethod() {
    return withNewDistinguisherMethodLike(
        getDistinguisherMethod() != null
            ? getDistinguisherMethod()
            : new V1beta1FlowDistinguisherMethodBuilder().build());
  }

  public V1beta1FlowSchemaSpecFluent.DistinguisherMethodNested<A> editOrNewDistinguisherMethodLike(
      V1beta1FlowDistinguisherMethod item) {
    return withNewDistinguisherMethodLike(
        getDistinguisherMethod() != null ? getDistinguisherMethod() : item);
  }

  public Integer getMatchingPrecedence() {
    return this.matchingPrecedence;
  }

  public A withMatchingPrecedence(Integer matchingPrecedence) {
    this.matchingPrecedence = matchingPrecedence;
    return (A) this;
  }

  public Boolean hasMatchingPrecedence() {
    return this.matchingPrecedence != null;
  }

  /**
   * This method has been deprecated, please use method buildPriorityLevelConfiguration instead.
   *
   * @return The buildable object.
   */
  @Deprecated
  public V1beta1PriorityLevelConfigurationReference getPriorityLevelConfiguration() {
    return this.priorityLevelConfiguration != null ? this.priorityLevelConfiguration.build() : null;
  }

  public V1beta1PriorityLevelConfigurationReference buildPriorityLevelConfiguration() {
    return this.priorityLevelConfiguration != null ? this.priorityLevelConfiguration.build() : null;
  }

  public A withPriorityLevelConfiguration(
      V1beta1PriorityLevelConfigurationReference priorityLevelConfiguration) {
    _visitables.get("priorityLevelConfiguration").remove(this.priorityLevelConfiguration);
    if (priorityLevelConfiguration != null) {
      this.priorityLevelConfiguration =
          new V1beta1PriorityLevelConfigurationReferenceBuilder(priorityLevelConfiguration);
      _visitables.get("priorityLevelConfiguration").add(this.priorityLevelConfiguration);
    } else {
      this.priorityLevelConfiguration = null;
      _visitables.get("priorityLevelConfiguration").remove(this.priorityLevelConfiguration);
    }
    return (A) this;
  }

  public Boolean hasPriorityLevelConfiguration() {
    return this.priorityLevelConfiguration != null;
  }

  public V1beta1FlowSchemaSpecFluent.PriorityLevelConfigurationNested<A>
      withNewPriorityLevelConfiguration() {
    return new V1beta1FlowSchemaSpecFluentImpl.PriorityLevelConfigurationNestedImpl();
  }

  public V1beta1FlowSchemaSpecFluent.PriorityLevelConfigurationNested<A>
      withNewPriorityLevelConfigurationLike(V1beta1PriorityLevelConfigurationReference item) {
    return new V1beta1FlowSchemaSpecFluentImpl.PriorityLevelConfigurationNestedImpl(item);
  }

  public V1beta1FlowSchemaSpecFluent.PriorityLevelConfigurationNested<A>
      editPriorityLevelConfiguration() {
    return withNewPriorityLevelConfigurationLike(getPriorityLevelConfiguration());
  }

  public V1beta1FlowSchemaSpecFluent.PriorityLevelConfigurationNested<A>
      editOrNewPriorityLevelConfiguration() {
    return withNewPriorityLevelConfigurationLike(
        getPriorityLevelConfiguration() != null
            ? getPriorityLevelConfiguration()
            : new V1beta1PriorityLevelConfigurationReferenceBuilder().build());
  }

  public V1beta1FlowSchemaSpecFluent.PriorityLevelConfigurationNested<A>
      editOrNewPriorityLevelConfigurationLike(V1beta1PriorityLevelConfigurationReference item) {
    return withNewPriorityLevelConfigurationLike(
        getPriorityLevelConfiguration() != null ? getPriorityLevelConfiguration() : item);
  }

  public A addToRules(Integer index, V1beta1PolicyRulesWithSubjects item) {
    if (this.rules == null) {
      this.rules = new ArrayList<V1beta1PolicyRulesWithSubjectsBuilder>();
    }
    V1beta1PolicyRulesWithSubjectsBuilder builder = new V1beta1PolicyRulesWithSubjectsBuilder(item);
    _visitables.get("rules").add(index >= 0 ? index : _visitables.get("rules").size(), builder);
    this.rules.add(index >= 0 ? index : rules.size(), builder);
    return (A) this;
  }

  public A setToRules(Integer index, V1beta1PolicyRulesWithSubjects item) {
    if (this.rules == null) {
      this.rules = new ArrayList<V1beta1PolicyRulesWithSubjectsBuilder>();
    }
    V1beta1PolicyRulesWithSubjectsBuilder builder = new V1beta1PolicyRulesWithSubjectsBuilder(item);
    if (index < 0 || index >= _visitables.get("rules").size()) {
      _visitables.get("rules").add(builder);
    } else {
      _visitables.get("rules").set(index, builder);
    }
    if (index < 0 || index >= rules.size()) {
      rules.add(builder);
    } else {
      rules.set(index, builder);
    }
    return (A) this;
  }

  public A addToRules(io.kubernetes.client.openapi.models.V1beta1PolicyRulesWithSubjects... items) {
    if (this.rules == null) {
      this.rules = new ArrayList<V1beta1PolicyRulesWithSubjectsBuilder>();
    }
    for (V1beta1PolicyRulesWithSubjects item : items) {
      V1beta1PolicyRulesWithSubjectsBuilder builder =
          new V1beta1PolicyRulesWithSubjectsBuilder(item);
      _visitables.get("rules").add(builder);
      this.rules.add(builder);
    }
    return (A) this;
  }

  public A addAllToRules(Collection<V1beta1PolicyRulesWithSubjects> items) {
    if (this.rules == null) {
      this.rules = new ArrayList<V1beta1PolicyRulesWithSubjectsBuilder>();
    }
    for (V1beta1PolicyRulesWithSubjects item : items) {
      V1beta1PolicyRulesWithSubjectsBuilder builder =
          new V1beta1PolicyRulesWithSubjectsBuilder(item);
      _visitables.get("rules").add(builder);
      this.rules.add(builder);
    }
    return (A) this;
  }

  public A removeFromRules(
      io.kubernetes.client.openapi.models.V1beta1PolicyRulesWithSubjects... items) {
    for (V1beta1PolicyRulesWithSubjects item : items) {
      V1beta1PolicyRulesWithSubjectsBuilder builder =
          new V1beta1PolicyRulesWithSubjectsBuilder(item);
      _visitables.get("rules").remove(builder);
      if (this.rules != null) {
        this.rules.remove(builder);
      }
    }
    return (A) this;
  }

  public A removeAllFromRules(Collection<V1beta1PolicyRulesWithSubjects> items) {
    for (V1beta1PolicyRulesWithSubjects item : items) {
      V1beta1PolicyRulesWithSubjectsBuilder builder =
          new V1beta1PolicyRulesWithSubjectsBuilder(item);
      _visitables.get("rules").remove(builder);
      if (this.rules != null) {
        this.rules.remove(builder);
      }
    }
    return (A) this;
  }

  public A removeMatchingFromRules(Predicate<V1beta1PolicyRulesWithSubjectsBuilder> predicate) {
    if (rules == null) return (A) this;
    final Iterator<V1beta1PolicyRulesWithSubjectsBuilder> each = rules.iterator();
    final List visitables = _visitables.get("rules");
    while (each.hasNext()) {
      V1beta1PolicyRulesWithSubjectsBuilder builder = each.next();
      if (predicate.test(builder)) {
        visitables.remove(builder);
        each.remove();
      }
    }
    return (A) this;
  }

  /**
   * This method has been deprecated, please use method buildRules instead.
   *
   * @return The buildable object.
   */
  @Deprecated
  public List<V1beta1PolicyRulesWithSubjects> getRules() {
    return rules != null ? build(rules) : null;
  }

  public List<V1beta1PolicyRulesWithSubjects> buildRules() {
    return rules != null ? build(rules) : null;
  }

  public V1beta1PolicyRulesWithSubjects buildRule(Integer index) {
    return this.rules.get(index).build();
  }

  public V1beta1PolicyRulesWithSubjects buildFirstRule() {
    return this.rules.get(0).build();
  }

  public V1beta1PolicyRulesWithSubjects buildLastRule() {
    return this.rules.get(rules.size() - 1).build();
  }

  public V1beta1PolicyRulesWithSubjects buildMatchingRule(
      Predicate<V1beta1PolicyRulesWithSubjectsBuilder> predicate) {
    for (V1beta1PolicyRulesWithSubjectsBuilder item : rules) {
      if (predicate.test(item)) {
        return item.build();
      }
    }
    return null;
  }

  public Boolean hasMatchingRule(Predicate<V1beta1PolicyRulesWithSubjectsBuilder> predicate) {
    for (V1beta1PolicyRulesWithSubjectsBuilder item : rules) {
      if (predicate.test(item)) {
        return true;
      }
    }
    return false;
  }

  public A withRules(List<V1beta1PolicyRulesWithSubjects> rules) {
    if (this.rules != null) {
      _visitables.get("rules").removeAll(this.rules);
    }
    if (rules != null) {
      this.rules = new ArrayList();
      for (V1beta1PolicyRulesWithSubjects item : rules) {
        this.addToRules(item);
      }
    } else {
      this.rules = null;
    }
    return (A) this;
  }

  public A withRules(io.kubernetes.client.openapi.models.V1beta1PolicyRulesWithSubjects... rules) {
    if (this.rules != null) {
      this.rules.clear();
    }
    if (rules != null) {
      for (V1beta1PolicyRulesWithSubjects item : rules) {
        this.addToRules(item);
      }
    }
    return (A) this;
  }

  public Boolean hasRules() {
    return rules != null && !rules.isEmpty();
  }

  public V1beta1FlowSchemaSpecFluent.RulesNested<A> addNewRule() {
    return new V1beta1FlowSchemaSpecFluentImpl.RulesNestedImpl();
  }

  public V1beta1FlowSchemaSpecFluent.RulesNested<A> addNewRuleLike(
      V1beta1PolicyRulesWithSubjects item) {
    return new V1beta1FlowSchemaSpecFluentImpl.RulesNestedImpl(-1, item);
  }

  public V1beta1FlowSchemaSpecFluent.RulesNested<A> setNewRuleLike(
      Integer index, V1beta1PolicyRulesWithSubjects item) {
    return new V1beta1FlowSchemaSpecFluentImpl.RulesNestedImpl(index, item);
  }

  public V1beta1FlowSchemaSpecFluent.RulesNested<A> editRule(Integer index) {
    if (rules.size() <= index) throw new RuntimeException("Can't edit rules. Index exceeds size.");
    return setNewRuleLike(index, buildRule(index));
  }

  public V1beta1FlowSchemaSpecFluent.RulesNested<A> editFirstRule() {
    if (rules.size() == 0) throw new RuntimeException("Can't edit first rules. The list is empty.");
    return setNewRuleLike(0, buildRule(0));
  }

  public V1beta1FlowSchemaSpecFluent.RulesNested<A> editLastRule() {
    int index = rules.size() - 1;
    if (index < 0) throw new RuntimeException("Can't edit last rules. The list is empty.");
    return setNewRuleLike(index, buildRule(index));
  }

  public V1beta1FlowSchemaSpecFluent.RulesNested<A> editMatchingRule(
      Predicate<V1beta1PolicyRulesWithSubjectsBuilder> predicate) {
    int index = -1;
    for (int i = 0; i < rules.size(); i++) {
      if (predicate.test(rules.get(i))) {
        index = i;
        break;
      }
    }
    if (index < 0) throw new RuntimeException("Can't edit matching rules. No match found.");
    return setNewRuleLike(index, buildRule(index));
  }

  public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    V1beta1FlowSchemaSpecFluentImpl that = (V1beta1FlowSchemaSpecFluentImpl) o;
    if (distinguisherMethod != null
        ? !distinguisherMethod.equals(that.distinguisherMethod)
        : that.distinguisherMethod != null) return false;
    if (matchingPrecedence != null
        ? !matchingPrecedence.equals(that.matchingPrecedence)
        : that.matchingPrecedence != null) return false;
    if (priorityLevelConfiguration != null
        ? !priorityLevelConfiguration.equals(that.priorityLevelConfiguration)
        : that.priorityLevelConfiguration != null) return false;
    if (rules != null ? !rules.equals(that.rules) : that.rules != null) return false;
    return true;
  }

  public int hashCode() {
    return java.util.Objects.hash(
        distinguisherMethod,
        matchingPrecedence,
        priorityLevelConfiguration,
        rules,
        super.hashCode());
  }

  public String toString() {
    StringBuilder sb = new StringBuilder();
    sb.append("{");
    if (distinguisherMethod != null) {
      sb.append("distinguisherMethod:");
      sb.append(distinguisherMethod + ",");
    }
    if (matchingPrecedence != null) {
      sb.append("matchingPrecedence:");
      sb.append(matchingPrecedence + ",");
    }
    if (priorityLevelConfiguration != null) {
      sb.append("priorityLevelConfiguration:");
      sb.append(priorityLevelConfiguration + ",");
    }
    if (rules != null && !rules.isEmpty()) {
      sb.append("rules:");
      sb.append(rules);
    }
    sb.append("}");
    return sb.toString();
  }

  class DistinguisherMethodNestedImpl<N>
      extends V1beta1FlowDistinguisherMethodFluentImpl<
          V1beta1FlowSchemaSpecFluent.DistinguisherMethodNested<N>>
      implements V1beta1FlowSchemaSpecFluent.DistinguisherMethodNested<N>, Nested<N> {
    DistinguisherMethodNestedImpl(V1beta1FlowDistinguisherMethod item) {
      this.builder = new V1beta1FlowDistinguisherMethodBuilder(this, item);
    }

    DistinguisherMethodNestedImpl() {
      this.builder = new V1beta1FlowDistinguisherMethodBuilder(this);
    }

    V1beta1FlowDistinguisherMethodBuilder builder;

    public N and() {
      return (N) V1beta1FlowSchemaSpecFluentImpl.this.withDistinguisherMethod(builder.build());
    }

    public N endDistinguisherMethod() {
      return and();
    }
  }

  class PriorityLevelConfigurationNestedImpl<N>
      extends V1beta1PriorityLevelConfigurationReferenceFluentImpl<
          V1beta1FlowSchemaSpecFluent.PriorityLevelConfigurationNested<N>>
      implements V1beta1FlowSchemaSpecFluent.PriorityLevelConfigurationNested<N>, Nested<N> {
    PriorityLevelConfigurationNestedImpl(V1beta1PriorityLevelConfigurationReference item) {
      this.builder = new V1beta1PriorityLevelConfigurationReferenceBuilder(this, item);
    }

    PriorityLevelConfigurationNestedImpl() {
      this.builder = new V1beta1PriorityLevelConfigurationReferenceBuilder(this);
    }

    V1beta1PriorityLevelConfigurationReferenceBuilder builder;

    public N and() {
      return (N)
          V1beta1FlowSchemaSpecFluentImpl.this.withPriorityLevelConfiguration(builder.build());
    }

    public N endPriorityLevelConfiguration() {
      return and();
    }
  }

  class RulesNestedImpl<N>
      extends V1beta1PolicyRulesWithSubjectsFluentImpl<V1beta1FlowSchemaSpecFluent.RulesNested<N>>
      implements V1beta1FlowSchemaSpecFluent.RulesNested<N>, Nested<N> {
    RulesNestedImpl(Integer index, V1beta1PolicyRulesWithSubjects item) {
      this.index = index;
      this.builder = new V1beta1PolicyRulesWithSubjectsBuilder(this, item);
    }

    RulesNestedImpl() {
      this.index = -1;
      this.builder = new V1beta1PolicyRulesWithSubjectsBuilder(this);
    }

    V1beta1PolicyRulesWithSubjectsBuilder builder;
    Integer index;

    public N and() {
      return (N) V1beta1FlowSchemaSpecFluentImpl.this.setToRules(index, builder.build());
    }

    public N endRule() {
      return and();
    }
  }
}
